#include "matrix.h"
#include "vector.h"

// ================================================================================================
// Overloaded operator functions
// ================================================================================================
Matrix4x4 Matrix4x4::operator*(Matrix4x4& b) {
    Matrix4x4 temp;

    // -- first row
    temp.m00 = m00*b.m00 + m01*b.m10 + m02*b.m20 + m03*b.m30;
    temp.m01 = m00*b.m01 + m01*b.m11 + m02*b.m21 + m03*b.m31;
    temp.m02 = m00*b.m02 + m01*b.m12 + m02*b.m22 + m03*b.m32;
    temp.m03 = m00*b.m03 + m01*b.m13 + m02*b.m23 + m03*b.m33;

    // -- second row
    temp.m10 = m10*b.m00 + m11*b.m10 + m12*b.m20 + m13*b.m30;
    temp.m11 = m10*b.m01 + m11*b.m11 + m12*b.m21 + m13*b.m31;
    temp.m12 = m10*b.m02 + m11*b.m12 + m12*b.m22 + m13*b.m32;
    temp.m13 = m10*b.m03 + m11*b.m13 + m12*b.m23 + m13*b.m33;

    // -- third row
    temp.m20 = m20*b.m00 + m21*b.m10 + m22*b.m20 + m23*b.m30;
    temp.m21 = m20*b.m01 + m21*b.m11 + m22*b.m21 + m23*b.m31;
    temp.m22 = m20*b.m02 + m21*b.m12 + m22*b.m22 + m23*b.m32;
    temp.m23 = m20*b.m03 + m21*b.m13 + m22*b.m23 + m23*b.m33;
    
    // -- fourth row
    temp.m30 = m30*b.m00 + m31*b.m10 + m32*b.m20 + m33*b.m30;
    temp.m31 = m30*b.m01 + m31*b.m11 + m32*b.m21 + m33*b.m31;
    temp.m32 = m30*b.m02 + m31*b.m12 + m32*b.m22 + m33*b.m32;
    temp.m33 = m30*b.m03 + m31*b.m13 + m32*b.m23 + m33*b.m33;

    return temp;
}

Matrix4x4 Matrix4x4::operator*=(Matrix4x4& b) {
    Matrix4x4 temp;

    // -- first row
    temp.m00 = m00*b.m00 + m01*b.m10 + m02*b.m20 + m03*b.m30;
    temp.m01 = m00*b.m01 + m01*b.m11 + m02*b.m21 + m03*b.m31;
    temp.m02 = m00*b.m02 + m01*b.m12 + m02*b.m22 + m03*b.m32;
    temp.m03 = m00*b.m03 + m01*b.m13 + m02*b.m23 + m03*b.m33;

    // -- second row
    temp.m10 = m10*b.m00 + m11*b.m10 + m12*b.m20 + m13*b.m30;
    temp.m11 = m10*b.m01 + m11*b.m11 + m12*b.m21 + m13*b.m31;
    temp.m12 = m10*b.m02 + m11*b.m12 + m12*b.m22 + m13*b.m32;
    temp.m13 = m10*b.m03 + m11*b.m13 + m12*b.m23 + m13*b.m33;

    // -- third row
    temp.m20 = m20*b.m00 + m21*b.m10 + m22*b.m20 + m23*b.m30;
    temp.m21 = m20*b.m01 + m21*b.m11 + m22*b.m21 + m23*b.m31;
    temp.m22 = m20*b.m02 + m21*b.m12 + m22*b.m22 + m23*b.m32;
    temp.m23 = m20*b.m03 + m21*b.m13 + m22*b.m23 + m23*b.m33;
    
    // -- fourth row
    temp.m30 = m30*b.m00 + m31*b.m10 + m32*b.m20 + m33*b.m30;
    temp.m31 = m30*b.m01 + m31*b.m11 + m32*b.m21 + m33*b.m31;
    temp.m32 = m30*b.m02 + m31*b.m12 + m32*b.m22 + m33*b.m32;
    temp.m33 = m30*b.m03 + m31*b.m13 + m32*b.m23 + m33*b.m33;

    *this = temp;

    return temp;
}

Matrix4x4 Matrix4x4::operator+(Matrix4x4& b) { 
    Matrix4x4 temp;

    // -- first row
    temp.m00 = m00 + b.m00;
    temp.m01 = m01 + b.m01;
    temp.m02 = m02 + b.m02;
    temp.m03 = m03 + b.m03;

    // -- second row
    temp.m10 = m10 + b.m10;
    temp.m11 = m11 + b.m11;
    temp.m12 = m12 + b.m12;
    temp.m13 = m13 + b.m13;

    // -- third row
    temp.m20 = m20 + b.m20;
    temp.m21 = m21 + b.m21;
    temp.m22 = m22 + b.m22;
    temp.m23 = m23 + b.m23;

    // -- fourth row
    temp.m30 = m30 + b.m30;
    temp.m31 = m31 + b.m31;
    temp.m32 = m32 + b.m32;
    temp.m33 = m33 + b.m33;

    return temp;
}

Matrix4x4 Matrix4x4::operator+=(Matrix4x4& b) { 
    Matrix4x4 temp;

    // -- first row
    temp.m00 = m00 + b.m00;
    temp.m01 = m01 + b.m01;
    temp.m02 = m02 + b.m02;
    temp.m03 = m03 + b.m03;

    // -- second row
    temp.m10 = m10 + b.m10;
    temp.m11 = m11 + b.m11;
    temp.m12 = m12 + b.m12;
    temp.m13 = m13 + b.m13;

    // -- third row
    temp.m20 = m20 + b.m20;
    temp.m21 = m21 + b.m21;
    temp.m22 = m22 + b.m22;
    temp.m23 = m23 + b.m23;

    // -- fourth row
    temp.m30 = m30 + b.m30;
    temp.m31 = m31 + b.m31;
    temp.m32 = m32 + b.m32;
    temp.m33 = m33 + b.m33;

    *this = temp;

    return temp;
}

// ==== End of Overloaded Operator functions ======================================================

// ================================================================================================
// Return the transpose of the matrix
// ================================================================================================
Matrix4x4 Matrix4x4::Transpose() {
    return Matrix4x4(m00, m10, m20, m30,
                     m01, m11, m21, m33,
                     m02, m12, m22, m32,
                     m03, m31, m23, m33);
}

// ================================================================================================
// Mutator methods
// ================================================================================================
void Matrix4x4::SetRow1(const Vector4& vec) { 
    m00 = vec.x;
    m01 = vec.y;
    m02 = vec.z;
}

void Matrix4x4::SetRow2(const Vector4& vec) { 
    m10 = vec.x;
    m11 = vec.y;
    m12 = vec.z;
}


void Matrix4x4::SetRow3(const Vector4& vec) { 
    m20 = vec.x;
    m21 = vec.y;
    m22 = vec.z;
}

void Matrix4x4::SetRow4(const Vector4& vec) {
    m30 = vec.x;
    m31 = vec.y;
    m32 = vec.z;
}
